home *** CD-ROM | disk | FTP | other *** search
/ Tech Arsenal 1 / Tech Arsenal (Arsenal Computer).ISO / tek-11 / exoapi.zip / EXOINT86.ZIP / CINT86X.C next >
C/C++ Source or Header  |  1993-06-15  |  10KB  |  277 lines

  1. /*
  2.  * File......: CINT86X.C
  3.  * Author....: Ted Means
  4.  * Date......: $Date:   15 Aug 1991 23:08:32  $
  5.  * Revision..: $Revision:   1.2  $
  6.  * Log file..: $Logfile:   E:/nanfor/src/cint86.c_v  $
  7.  *
  8.  * This function is an original work by Ted Means and is placed in the
  9.  * public domain.
  10.  *
  11.  * Modification history:
  12.  * ---------------------
  13.  *
  14.  * $Log:   E:/nanfor/src/cint86.c_v  $
  15.  *
  16.  *    Rev 1.3    6 Jun 1993 19:30:12
  17.  * Anton van Straaten modified for ExoSpace;
  18.  * this version is ExoSpace-specific.
  19.  *
  20.  *    Rev 1.2   15 Aug 1991 23:08:32   GLENN
  21.  * Forest Belt proofread/edited/cleaned up doc
  22.  *
  23.  *    Rev 1.1   14 Jun 1991 03:48:42   GLENN
  24.  * Just corrected some typos in the documentation.
  25.  *
  26.  *    Rev 1.0   27 May 1991 13:22:36   GLENN
  27.  * Initial revision.
  28.  *
  29.  *
  30.  
  31.  *  $DOC$
  32.  *  $FUNCNAME$
  33.  *      FT_INT86()
  34.  *  $CATEGORY$
  35.  *      DOS/BIOS
  36.  *  $ONELINER$
  37.  *      Execute a software interrupt
  38.  *  $SYNTAX$
  39.  *      FT_INT86( <nInterruptNumber>, <aRegisterValues> ) -> lResult
  40.  *  $ARGUMENTS$
  41.  *      <nInterruptNumber> is the interrupt to execute.
  42.  *
  43.  *      <aRegisterValues> is an array that contains values to be loaded
  44.  *      into the various CPU registers.  The correspondence between
  45.  *      registers and array elements is as follows:
  46.  *
  47.  *               aElement[1]  ==  AX register
  48.  *               aElement[2]  ==  BX register
  49.  *               aElement[3]  ==  CX register
  50.  *               aElement[4]  ==  DX register
  51.  *               aElement[5]  ==  SI register
  52.  *               aElement[6]  ==  DI register
  53.  *               aElement[7]  ==  BP register
  54.  *               aElement[8]  ==  DS register
  55.  *               aElement[9]  ==  ES register
  56.  *               aElement[10] ==  Flags register
  57.  *  $RETURNS$
  58.  *      .T. if all parameters valid and the function was able
  59.  *          to execute the desired interrupt.
  60.  *      .F. if invalid parameters passed.
  61.  *
  62.  *     In addition, the array elements will contain whatever values were in
  63.  *     the CPU registers immediately after the interrupt was executed.  If
  64.  *     either of the string parameters were altered by the interrupt, these
  65.  *     changes will be reflected as well.
  66.  *
  67.  *  $DESCRIPTION$
  68.  *     It is occasionally useful to be able to call interrupts directly from
  69.  *     Clipper, without having to write a separate routine in C or ASM.  This
  70.  *     function allows you that capability.
  71.  *
  72.  *     Given Clipper's high-level orientation, this function is necessarily
  73.  *     somewhat messy to use.  First, declare an array of ten elements to
  74.  *     hold the eight values for the CPU registers and two string parameters.
  75.  *     Then initialize the array elements with the values that you want the
  76.  *     CPU registers to contain when the interrupt is executed.  You need not
  77.  *     initialize all the elements.  For example, if the interrupt requires
  78.  *     you to specify values for AX, DX, and DS, you would only need to
  79.  *     initialize elements 1, 4, and 8.
  80.  *
  81.  *     Once you have done the required register setup, call FT_INT86(),
  82.  *     passing the interrupt number and the register array as parameters.
  83.  *     The function will load the CPU with your specified values, execute the
  84.  *     interrupt, and then store the contents of the CPU registers back into
  85.  *     your array.  This will allow you to evaluate the results of the
  86.  *     interrupt.
  87.  *
  88.  *     Some interrupt services require you to pass the address of a string in
  89.  *     a pair of registers.  This function is capable of handling these sorts
  90.  *     of situations, but it will take a little work on your part.  If you need
  91.  *     to pass a string that uses the DS register, store the string in element
  92.  *     8;  if you need to pass a string that uses the ES register, store the
  93.  *     string in element 9.  FT_INT86() will detect that you've supplied a
  94.  *     string instead of a numeric value and will behave accordingly.
  95.  *
  96.  *     That takes care of obtaining the segment portion of the pointer.  To
  97.  *     specify which register is to contain the offset, use the values REG_DS
  98.  *     and REG_ES which are defined in the FTINT86.CH file.  When one of these
  99.  *     values is found in an array element, it alerts FT_Int86() to use the
  100.  *     offset portion of a pointer instead of a numeric value.  REG_DS tells
  101.  *     FT_Int86() to use the offset of the string in element 8, while REG_ES
  102.  *     tells FT_Int86() to use the offset of the string in element 9.
  103.  *
  104.  *     All the CPU registers are sixteen bits in size.  Some, however, are
  105.  *     also split into two 8-bit registers.  This function is only capable of
  106.  *     receiving and returning registers that are 16 bits in size.  To split
  107.  *     a 16-bit register into two 8-bit values, you can use the
  108.  *     pseudo-functions HighByte() and LowByte(), contained in the .CH file.
  109.  *
  110.  *     To alter an 8-bit number so it will appear in the high-order byte of a
  111.  *     register when passed to the FT_INT86() function, use the MakeHI()
  112.  *     pseudo-function contained in the .CH file.
  113.  *
  114.  *     This function is a shell for __ftint86(), which is written in assembler
  115.  *     and does the actual work of executing the interrupt.  __ftint86() is
  116.  *     callable from C, so feel free to incorporate it into any C routines
  117.  *     for which it might be useful.  The source for __ftint86() can be found
  118.  *     in the file AINT86.ASM.
  119.  *  $EXAMPLES$
  120.  *
  121.  *     * This example shows how to call the DOS "create file" service.  Take
  122.  *     * special note of how to set up string parameters.
  123.  *
  124.  *     #include "FTINT86.CH"
  125.  *
  126.  *     local aRegs[10]              // Declare the register array
  127.  *     aRegs[ AX ] := makehi(60)    // DOS service, create file
  128.  *     aRegs[ CX ] := 0             // Specify file attribute
  129.  *
  130.  *     * Pay attention here, this is crucial.  Note how to set up the string
  131.  *     * so it appears in DS:DX.
  132.  *
  133.  *     aRegs[ DS ] := "C:\MISC\MYFILE.XXX"
  134.  *     aRegs[ DX ] := REG_DS
  135.  *     FT_INT86( 33, aRegs)         // Make the call to the DOS interrupt
  136.  *
  137.  *
  138.  *
  139.  *     * This example shows how to call the DOS "get current directory"
  140.  *     * service.  This one also uses a string parameter, but note that it
  141.  *     * uses a different offset register.
  142.  *
  143.  *     #include "FTINT86.CH"
  144.  *
  145.  *     local aRegs[10]
  146.  *     aRegs[ AX ] := makehi(71)
  147.  *     aRegs[ DX ] := 0           // Choose default drive
  148.  *
  149.  *     * This service requires a 64-byte buffer whose address is in DS:SI.  DOS
  150.  *     * will fill the buffer with the current directory.
  151.  *
  152.  *     aRegs[ DS ] := space(64)
  153.  *     aRegs[ SI ] := REG_DS
  154.  *     FT_INT86( 33, aRegs)
  155.  *
  156.  *     ? aRegs[ DS ]       // Display the directory name
  157.  *
  158.  *
  159.  *
  160.  *     * For the sake of completeness, here's an example that doesn't use a
  161.  *     * string.  This one changes the video mode.
  162.  *
  163.  *     #include "FTINT86.CH"
  164.  *
  165.  *     local aRegs[10]
  166.  *
  167.  *     aRegs[ AX ] := 16          // Choose hi-res graphics
  168.  *     FT_INT86( 16, aRegs)
  169.  *  $INCLUDE$
  170.  *     FTINT86.CH
  171.  *  $END$
  172. */
  173.  
  174. #include "extend.h"
  175. #include "exoapi.h"
  176.  
  177. // _bcopy is in CLIPPER.LIB and is useful for copying
  178. // memory blocks.  Perhaps NanFor has a similar function?  tbd.
  179. void *_bcopy( void *tgt, void *src, unsigned nBytes );
  180.  
  181. /*
  182.    setReg() is a macro which sets a register value in a D16REGS structure,
  183.    using an offset into the FT_INT86 register array.  The regOff array
  184.    defined below maps an offset into the FT_INT86 register array to an
  185.    offset into the D16REGS structure.  The numbers are offsets into the
  186.    D16REGS structure.
  187.  
  188.    This approach is used because changing the FT_INT86 register array
  189.    sequence would mean that existing code would have to be modified or
  190.    recompiled, and/or there would be a discrepancy between the real and
  191.    protected mode versions of the library.
  192.  
  193.                        AX BX CX DX SI DI BP     */
  194. static int regOff[] = { 9, 6, 8, 7, 3, 2, 4 };
  195.  
  196. #define getReg(regs, n)      (((unsigned *) &(regs))[ regOff[ (n) - 1 ] ])
  197. #define setReg(regs, n, val) (getReg((regs), (n)) = (val))
  198.  
  199. // macros to extract segment and offset from a far pointer
  200. // (in Borland and MS dos.h)
  201. #define FP_SEG( fp )    ( ( unsigned )((( unsigned long )( fp )) >> 16) )
  202. #define FP_OFF( fp )    ( ( unsigned )( fp ))
  203.  
  204.  
  205. CLIPPER FT_Int86( void )
  206. {
  207.    auto int n;
  208.    auto EXOREGS regs;
  209.    auto void far *dsPtr;            // for real-mode pointer to buffer
  210.    auto void far *esPtr;
  211.    auto char far *dsBuf = NULL;     // for protected-mode pointer to buffer
  212.    auto char far *esBuf = NULL;
  213.    auto int nLenDS, nLenES;
  214.  
  215.    if ( ( PCOUNT == 2 ) && ISNUM( 1 ) && ISARRAY( 2 ) )
  216.    {
  217.       if ( _parinfa( 2, 8 ) & CHARACTER )
  218.       {
  219.          nLenDS = _parclen( 2, 8 );
  220.          dsBuf = _xalloclow( nLenDS + 1 );
  221.          dsBuf[ nLenDS ] = 0;                       // in case of ASCIIZ
  222.          _bcopy( dsBuf, _parc( 2, 8 ), nLenDS );
  223.          dsPtr = ExoRealPtr( dsBuf );
  224.          regs.ds = FP_SEG( dsPtr );
  225.       }
  226.       else
  227.          regs.ds = _parni( 2, 8 );
  228.  
  229.       if ( _parinfa( 2, 9 ) & CHARACTER )
  230.       {
  231.          nLenES = _parclen( 2, 9 );
  232.          esBuf = _xalloclow( nLenES + 1 );
  233.          esBuf[ nLenES ] = 0;                       // in case of ASCIIZ
  234.          _bcopy( esBuf, _parc( 2, 9 ), nLenES );
  235.          esPtr = ExoRealPtr( esBuf );
  236.          regs.es = FP_SEG( esPtr );
  237.       }
  238.       else
  239.          regs.es = _parni( 2, 9 );
  240.  
  241.       for ( n = 1; n <= 7; n++ )
  242.       {
  243.          if ( _parinfa( 2, n ) & LOGICAL )
  244.             setReg( regs, n, _parl( 2, n ) ? FP_OFF( dsPtr ) : FP_OFF( esPtr ) );
  245.          else
  246.             setReg( regs, n, _parni( 2, n ) );
  247.       }
  248.  
  249.       // ExoRMInterrupt() returns the flags
  250.       _storni( ExoRMInterrupt( _parni( 1 ), ®s, ®s ), 2, 10 );
  251.  
  252.       for ( n = 1; n <= 7; n++ )
  253.          _storni( getReg(regs, n), 2, n );
  254.  
  255.       if ( dsBuf ) {
  256.          _storclen( NULL, nLenDS, 2, 8 );
  257.          _bcopy( _parc( 2, 8 ), dsBuf, nLenDS );
  258.          _xfreelow( dsBuf );
  259.       } else
  260.          _storni( regs.ds, 2, 8 );
  261.  
  262.       if ( esBuf ) {
  263.          _storclen( NULL, nLenES, 2, 9 );
  264.          _bcopy( _parc( 2, 9 ), esBuf, nLenES );
  265.          _xfreelow( esBuf );
  266.       } else
  267.          _storni( regs.es, 2, 9 );
  268.  
  269.       _retl( TRUE );
  270.    }
  271.    else
  272.       _retl( FALSE );
  273.  
  274.    return;
  275. }
  276.  
  277.